"""飞书API服务"""
import os
import sys

# 添加项目根目录到Python路径
current_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(current_dir)

import requests
import json
from typing import List, Dict, Any, Optional
from datetime import datetime, timedelta
from config.feishu_config import FEISHU_CONFIG, FEISHU_TABLE_URLS
from utils.logger import sync_logger

class FeishuService:
    def __init__(self):
        self.config = FEISHU_CONFIG
        self.token = None
        self.token_expire_time = None
        sync_logger.log_info("飞书服务初始化完成")
    
    def _get_access_token(self):
        """获取飞书应用访问令牌"""
        try:
            # 检查现有令牌是否有效
            if self.token and self.token_expire_time and datetime.now() < self.token_expire_time:
                sync_logger.log_info("使用现有访问令牌")
                return self.token
            
            sync_logger.log_info("开始获取新的访问令牌")
            url = "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal"
            headers = {
                "Content-Type": "application/json"
            }
            data = {
                "app_id": self.config["app_id"],
                "app_secret": self.config["app_secret"]
            }
            
            sync_logger.log_info(f"请求URL: {url}")
            sync_logger.log_info(f"请求头: {headers}")
            sync_logger.log_info(f"请求数据: {data}")
            
            response = requests.post(url, headers=headers, json=data, timeout=self.config["timeout"])
            
            # 记录原始响应内容
            sync_logger.log_info(f"原始响应内容: {response.text}")
            
            try:
                result = response.json()
            except json.JSONDecodeError as e:
                error_msg = f"解析响应JSON失败: {str(e)}, 响应内容: {response.text}"
                sync_logger.log_error(error_msg)
                raise Exception(error_msg)
            
            sync_logger.log_info(f"响应状态码: {response.status_code}")
            sync_logger.log_info(f"响应内容: {result}")
            
            if result.get("code") == 0:
                self.token = result.get("tenant_access_token")
                expire_seconds = result.get("expire", 7200)  # 默认2小时
                self.token_expire_time = datetime.now() + timedelta(seconds=expire_seconds - 300)  # 提前5分钟刷新
                sync_logger.log_info("成功获取新的访问令牌")
                return self.token
            else:
                error_msg = f"获取飞书访问令牌失败: {result}"
                sync_logger.log_error(error_msg)
                raise Exception(error_msg)
                
        except requests.exceptions.RequestException as e:
            error_msg = f"请求飞书API时发生网络错误: {str(e)}"
            sync_logger.log_error(error_msg)
            raise Exception(error_msg)
        except Exception as e:
            error_msg = f"获取飞书访问令牌时发生未知错误: {str(e)}"
            sync_logger.log_error(error_msg)
            raise Exception(error_msg)
    
    def get_table_fields(self) -> List[Dict[str, Any]]:
        """获取飞书多维表的字段信息"""
        try:
            token = self._get_access_token()
            if not token:
                raise Exception("无法获取访问令牌")
            
            # 修改URL格式，使用正确的API路径
            url = f"https://open.feishu.cn/open-apis/bitable/v1/apps/{self.config['app_token']}/tables/{self.config['table_id']}/fields"
            headers = {
                "Authorization": f"Bearer {token}",
                "Content-Type": "application/json"
            }
            
            sync_logger.log_info(f"请求URL: {url}")
            sync_logger.log_info(f"请求头: {headers}")
            
            response = requests.get(url, headers=headers, timeout=self.config["timeout"])
            
            # 记录原始响应内容
            sync_logger.log_info(f"原始响应内容: {response.text}")
            
            # 检查HTTP状态码
            if response.status_code != 200:
                error_msg = f"HTTP请求失败，状态码: {response.status_code}, 响应内容: {response.text}"
                sync_logger.log_error(error_msg)
                raise Exception(error_msg)
            
            try:
                result = response.json()
            except json.JSONDecodeError as e:
                error_msg = f"解析响应JSON失败: {str(e)}, 响应内容: {response.text}"
                sync_logger.log_error(error_msg)
                raise Exception(error_msg)
            
            sync_logger.log_info(f"响应状态码: {response.status_code}")
            sync_logger.log_info(f"响应内容: {result}")
            
            if result.get("code") == 0:
                fields = result.get("data", {}).get("items", [])
                sync_logger.log_info(f"成功获取到 {len(fields)} 个字段")
                return fields
            else:
                error_msg = f"获取多维表字段信息失败: {result}"
                sync_logger.log_error(error_msg)
                raise Exception(error_msg)
                
        except requests.exceptions.RequestException as e:
            error_msg = f"请求飞书API时发生网络错误: {str(e)}"
            sync_logger.log_error(error_msg)
            raise Exception(error_msg)
        except Exception as e:
            error_msg = f"获取多维表字段信息时发生未知错误: {str(e)}"
            sync_logger.log_error(error_msg)
            raise Exception(error_msg)
    
    def get_table_records(self, last_modified_time: Optional[str] = None) -> List[Dict[str, Any]]:
        """获取飞书多维表的记录"""
        try:
            token = self._get_access_token()
            if not token:
                raise Exception("无法获取访问令牌")
            
            # 获取字段信息
            fields = self.get_table_fields()
            update_time_field = None
            for field in fields:
                if field.get('type') == 'DateTime' and 'update' in field.get('field_name', '').lower():
                    update_time_field = field.get('field_name')
                    break
            
            if not update_time_field:
                sync_logger.log_info("未找到更新时间字段，将获取所有记录")
            
            # 修改URL格式，使用正确的API路径
            url = f"https://open.feishu.cn/open-apis/bitable/v1/apps/{self.config['app_token']}/tables/{self.config['table_id']}/records"
            headers = {
                "Authorization": f"Bearer {token}",
                "Content-Type": "application/json"
            }
            
            params = {}
            if last_modified_time and update_time_field:
                params["filter"] = f"CurrentValue.[{update_time_field}] > '{last_modified_time}'"
            
            sync_logger.log_info(f"请求URL: {url}")
            sync_logger.log_info(f"请求头: {headers}")
            sync_logger.log_info(f"请求参数: {params}")
            
            records = []
            page_token = None
            
            while True:
                if page_token:
                    params["page_token"] = page_token
                
                response = requests.get(url, headers=headers, params=params, timeout=self.config["timeout"])
                
                # 检查HTTP状态码
                if response.status_code != 200:
                    error_msg = f"HTTP请求失败，状态码: {response.status_code}, 响应内容: {response.text}"
                    sync_logger.log_error(error_msg)
                    raise Exception(error_msg)
                
                # 记录原始响应内容
                sync_logger.log_info(f"原始响应内容: {response.text}")
                
                try:
                    result = response.json()
                except json.JSONDecodeError as e:
                    error_msg = f"解析响应JSON失败: {str(e)}, 响应内容: {response.text}"
                    sync_logger.log_error(error_msg)
                    raise Exception(error_msg)
                
                sync_logger.log_info(f"响应状态码: {response.status_code}")
                sync_logger.log_info(f"响应内容: {result}")
                
                if result.get("code") == 0:
                    page_records = result.get("data", {}).get("items", [])
                    records.extend(page_records)
                    
                    page_token = result.get("data", {}).get("page_token")
                    has_more = result.get("data", {}).get("has_more")
                    
                    if not has_more or not page_token:
                        break
                else:
                    error_msg = f"获取多维表记录失败: {result}"
                    sync_logger.log_error(error_msg)
                    raise Exception(error_msg)
            
            sync_logger.log_info(f"成功获取到 {len(records)} 条记录")
            return records
            
        except requests.exceptions.RequestException as e:
            error_msg = f"请求飞书API时发生网络错误: {str(e)}"
            sync_logger.log_error(error_msg)
            raise Exception(error_msg)
        except Exception as e:
            error_msg = f"获取多维表记录时发生未知错误: {str(e)}"
            sync_logger.log_error(error_msg)
            raise Exception(error_msg)

    def get_table_fields_by_token(self, app_token: str, table_id: str):
        """获取指定多维表的字段信息"""
        token = self._get_access_token()
        url = f"https://open.feishu.cn/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/fields"
        headers = {
            "Authorization": f"Bearer {token}",
            "Content-Type": "application/json"
        }
        response = requests.get(url, headers=headers, timeout=self.config["timeout"])
        if response.status_code != 200:
            sync_logger.log_error(f"获取字段信息失败，状态码: {response.status_code}, 响应: {response.text}")
            raise Exception(f"获取字段信息失败: {response.text}")
        result = response.json()
        if result.get("code") == 0:
            return result.get("data", {}).get("items", [])
        else:
            sync_logger.log_error(f"获取字段信息失败: {result}")
            raise Exception(f"获取字段信息失败: {result}")

    def get_table_records_by_token(self, app_token: str, table_id: str):
        """获取指定多维表的数据"""
        token = self._get_access_token()
        url = f"https://open.feishu.cn/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/records"
        headers = {
            "Authorization": f"Bearer {token}",
            "Content-Type": "application/json"
        }
        records = []
        page_token = None
        while True:
            params = {}
            if page_token:
                params["page_token"] = page_token
            response = requests.get(url, headers=headers, params=params, timeout=self.config["timeout"])
            if response.status_code != 200:
                sync_logger.log_error(f"获取表数据失败，状态码: {response.status_code}, 响应: {response.text}")
                raise Exception(f"获取表数据失败: {response.text}")
            result = response.json()
            if result.get("code") == 0:
                items = result.get("data", {}).get("items", [])
                for item in items:
                    # 只保留fields部分
                    records.append(item.get("fields", {}))
                page_token = result.get("data", {}).get("page_token")
                has_more = result.get("data", {}).get("has_more")
                if not has_more or not page_token:
                    break
            else:
                sync_logger.log_error(f"获取表数据失败: {result}")
                raise Exception(f"获取表数据失败: {result}")
        return records

    def get_table_info_by_mcp(self, app_token: str, table_id: str):
        """使用飞书MCP接口获取表信息
        
        飞书MCP接口通常用于内部系统和官方应用，可能与开放平台API有所不同
        但在某些情况下，MCP接口更稳定且能提供更完整的表信息
        """
        token = self._get_access_token()
        
        # 飞书MCP接口
        mcp_url = f"https://mcp.feishu.cn/suite/bitable/open-apis/table-manage/v1/apps/{app_token}/tables/{table_id}/infomation"
        headers = {
            "Authorization": f"Bearer {token}",
            "Content-Type": "application/json"
        }
        
        sync_logger.log_info(f"尝试通过MCP接口获取表信息: {mcp_url}")
        
        try:
            response = requests.get(mcp_url, headers=headers, timeout=self.config["timeout"])
            sync_logger.log_info(f"MCP接口响应状态码: {response.status_code}")
            
            if response.status_code == 200:
                result = response.json()
                sync_logger.log_info(f"MCP接口返回数据: {result}")
                if result.get("code") == 0:
                    table_name = result.get("data", {}).get("table_name", "")
                    if table_name:
                        sync_logger.log_info(f"成功从MCP接口获取表名: {table_name}")
                        return {"name": table_name}
        except Exception as e:
            sync_logger.log_error(f"通过MCP接口获取表名失败: {str(e)}")
        
        # 尝试另一个可能的MCP接口路径
        alternative_url = f"https://internal-api.feishu.cn/suite/bitable/open-apis/table-manage/v1/apps/{app_token}/tables/{table_id}"
        sync_logger.log_info(f"尝试通过备选MCP接口获取表信息: {alternative_url}")
        
        try:
            alt_response = requests.get(alternative_url, headers=headers, timeout=self.config["timeout"])
            sync_logger.log_info(f"备选MCP接口响应状态码: {alt_response.status_code}")
            
            if alt_response.status_code == 200:
                alt_result = alt_response.json()
                if alt_result.get("code") == 0:
                    table_name = alt_result.get("data", {}).get("name", "")
                    if table_name:
                        sync_logger.log_info(f"成功从备选MCP接口获取表名: {table_name}")
                        return {"name": table_name}
        except Exception as e:
            sync_logger.log_error(f"通过备选MCP接口获取表名失败: {str(e)}")
            
        return None

    def get_table_info_by_web(self, app_token: str, table_id: str):
        """通过Web方式获取表信息
        
        飞书Web界面会加载表的详细信息，可以从中提取表名
        这种方法模拟浏览器行为，不依赖API权限
        """
        # 构建飞书多维表格的访问URL
        web_url = f"https://wx6lpdt35j.feishu.cn/base/{app_token}?table={table_id}"
        headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
            "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
            "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8"
        }
        
        sync_logger.log_info(f"尝试通过Web界面获取表信息: {web_url}")
        
        try:
            # 获取页面内容
            response = requests.get(web_url, headers=headers, timeout=30)  # 网页可能加载较慢，增加超时时间
            sync_logger.log_info(f"Web界面响应状态码: {response.status_code}")
            
            if response.status_code == 200:
                # 在HTML内容中查找表名
                html_content = response.text
                
                # 飞书页面通常会在title中包含表名
                import re
                title_match = re.search(r'<title>(.*?)</title>', html_content)
                if title_match:
                    title = title_match.group(1)
                    # 提取表名（通常是形如"表名 - 飞书多维表格"）
                    table_name = title.split(' - ')[0].strip()
                    if table_name:
                        sync_logger.log_info(f"从Web页面标题提取到表名: {table_name}")
                        return {"name": table_name}
                
                # 查找可能包含表名的JSON数据
                json_pattern = re.search(r'window\.LPS_BITABLE_INIT_STATE\s*=\s*({.*?});', html_content, re.DOTALL)
                if json_pattern:
                    try:
                        import json
                        json_data = json.loads(json_pattern.group(1))
                        # 在初始化数据中查找表名
                        meta_data = json_data.get('meta', {})
                        table_name = meta_data.get('name', '')
                        if table_name:
                            sync_logger.log_info(f"从Web页面JSON数据提取到表名: {table_name}")
                            return {"name": table_name}
                    except Exception as e:
                        sync_logger.log_error(f"解析Web页面JSON数据失败: {str(e)}")
                
                # 尝试直接搜索特定文本模式
                # 从URL中获取表名称
                table_id_match = re.search(r'"tableId":"([^"]*)"[^}]*"name":"([^"]*)"', html_content)
                if table_id_match:
                    found_table_id = table_id_match.group(1)
                    if found_table_id == table_id:
                        table_name = table_id_match.group(2)
                        sync_logger.log_info(f"从Web页面文本模式提取到表名: {table_name}")
                        return {"name": table_name}
        except Exception as e:
            sync_logger.log_error(f"通过Web界面获取表名失败: {str(e)}")
            
        return None

    def get_table_info_by_token(self, app_token: str, table_id: str):
        """获取指定多维表的基本信息，包括表名"""
        token = self._get_access_token()
        
        # 0. 首先尝试使用MCP接口获取表名，这通常更可靠
        mcp_result = self.get_table_info_by_mcp(app_token, table_id)
        if mcp_result and mcp_result.get("name"):
            return mcp_result
            
        # 0.1 尝试通过Web方式获取表名
        web_result = self.get_table_info_by_web(app_token, table_id)
        if web_result and web_result.get("name"):
            return web_result
        
        # 1. 尝试获取表详情
        url = f"https://open.feishu.cn/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}"
        headers = {
            "Authorization": f"Bearer {token}",
            "Content-Type": "application/json"
        }
        
        # 记录详细信息，方便调试
        sync_logger.log_info(f"尝试获取表信息，URL: {url}")
        sync_logger.log_info(f"Authorization: Bearer {token[:10]}...")
            
        try:
            response = requests.get(url, headers=headers, timeout=self.config["timeout"])
            sync_logger.log_info(f"表信息API响应状态码: {response.status_code}")
            sync_logger.log_info(f"表信息API响应内容: {response.text[:200]}...")
            
            if response.status_code == 200:
                result = response.json()
                if result.get("code") == 0:
                    table_info = result.get("data", {})
                    table_name = table_info.get("name", "")
                    if table_name:
                        sync_logger.log_info(f"成功从API直接获取表名: {table_name}")
                        return {"name": table_name}
        except Exception as e:
            sync_logger.log_error(f"直接获取表信息失败: {str(e)}")
            
        # 2. 尝试通过视图接口获取表名
        try:
            views_url = f"https://open.feishu.cn/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/views"
            sync_logger.log_info(f"尝试通过视图API获取表名，URL: {views_url}")
            
            views_response = requests.get(views_url, headers=headers, timeout=self.config["timeout"])
            sync_logger.log_info(f"视图API响应状态码: {views_response.status_code}")
            
            if views_response.status_code == 200:
                views_result = views_response.json()
                if views_result.get("code") == 0:
                    views = views_result.get("data", {}).get("items", [])
                    if views and len(views) > 0:
                        # 视图API中通常包含表名
                        table_name = views[0].get("table_name", "")
                        if table_name:
                            sync_logger.log_info(f"成功从视图API获取表名: {table_name}")
                            return {"name": table_name}
        except Exception as e:
            sync_logger.log_error(f"通过视图获取表名失败: {str(e)}")
            
        # 3. 尝试获取记录信息，记录中有可能包含表名
        try:
            records_url = f"https://open.feishu.cn/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/records?page_size=1"
            sync_logger.log_info(f"尝试通过记录API获取表信息，URL: {records_url}")
            
            records_response = requests.get(records_url, headers=headers, timeout=self.config["timeout"])
            sync_logger.log_info(f"记录API响应状态码: {records_response.status_code}")
            
            if records_response.status_code == 200:
                records_result = records_response.json()
                if records_result.get("code") == 0:
                    # 某些API返回中可能包含表名
                    table_name = records_result.get("data", {}).get("table_name", "")
                    if table_name:
                        sync_logger.log_info(f"成功从记录API获取表名: {table_name}")
                        return {"name": table_name}
        except Exception as e:
            sync_logger.log_error(f"通过记录获取表名失败: {str(e)}")
        
        # 如果API调用全部失败，降级到URL解析推断
        sync_logger.log_info("API获取表名全部失败，尝试从URL推断表名")
        for config_url in FEISHU_TABLE_URLS:
            try:
                if table_id in config_url:
                    # 从URL中提取可能的表名
                    parts = config_url.split("/")
                    for i, part in enumerate(parts):
                        if part == "base" and i+1 < len(parts):
                            base_name = parts[i+1].split("?")[0]
                            sync_logger.log_info(f"从URL推断表名: base_{base_name}")
                            return {"name": f"base_{base_name}"}
            except Exception:
                pass
                
        # 硬编码特定表
        if table_id == "tblvpF1mcn10hcDa":
            sync_logger.log_info(f"使用硬编码表名: 缺陷管理表")
            return {"name": "缺陷管理表"}
            
        # 最后的后备方案
        default_name = f"table_{table_id}"
        sync_logger.log_info(f"使用默认表名: {default_name}")
        return {"name": default_name}

    def get_all_tables(self, app_token: str = None) -> List[Dict[str, Any]]:
        """获取应用下所有表的信息
        
        Args:
            app_token: 应用token，如果为None则使用配置中的app_token
            
        Returns:
            表列表，每个表包含id和name信息
        """
        try:
            token = self._get_access_token()
            if not token:
                raise Exception("无法获取访问令牌")
                
            # 使用传入的app_token或配置中的app_token
            app_token = app_token or self.config['app_token']
            
            # 飞书API获取应用下所有表
            url = f"https://open.feishu.cn/open-apis/bitable/v1/apps/{app_token}/tables"
            headers = {
                "Authorization": f"Bearer {token}",
                "Content-Type": "application/json"
            }
            
            sync_logger.log_info(f"开始获取应用下所有表信息，URL: {url}")
            
            response = requests.get(url, headers=headers, timeout=self.config["timeout"])
            
            # 记录原始响应内容，便于调试
            sync_logger.log_info(f"原始响应状态码: {response.status_code}")
            sync_logger.log_info(f"原始响应内容: {response.text[:200]}...")
            
            # 检查HTTP状态码
            if response.status_code != 200:
                error_msg = f"HTTP请求失败，状态码: {response.status_code}, 响应内容: {response.text}"
                sync_logger.log_error(error_msg)
                raise Exception(error_msg)
            
            try:
                result = response.json()
            except json.JSONDecodeError as e:
                error_msg = f"解析响应JSON失败: {str(e)}, 响应内容: {response.text}"
                sync_logger.log_error(error_msg)
                raise Exception(error_msg)
            
            if result.get("code") == 0:
                tables = result.get("data", {}).get("items", [])
                sync_logger.log_info(f"成功获取到 {len(tables)} 个表")
                
                # 整理返回结果，只保留id和name
                table_info = []
                for table in tables:
                    table_id = table.get("table_id", "")
                    table_name = table.get("name", "")
                    
                    if table_id:
                        # 处理表名，确保有意义
                        if not table_name:
                            table_name = f"table_{table_id}"
                        
                        table_info.append({
                            "id": table_id,
                            "name": table_name
                        })
                        
                        sync_logger.log_info(f"表信息: ID={table_id}, 名称={table_name}")
                
                return table_info
            else:
                error_msg = f"获取表列表失败: {result}"
                sync_logger.log_error(error_msg)
                raise Exception(error_msg)
                
        except requests.exceptions.RequestException as e:
            error_msg = f"请求飞书API时发生网络错误: {str(e)}"
            sync_logger.log_error(error_msg)
            raise Exception(error_msg)
        except Exception as e:
            error_msg = f"获取表列表时发生未知错误: {str(e)}"
            sync_logger.log_error(error_msg)
            raise Exception(error_msg) 